package com.bachongLightNovel.system.service.impl;

import cn.hutool.core.util.StrUtil;
import com.bachongLightNovel.constant.RedisConstant;
import com.bachongLightNovel.model.dto.system.PasswordDto;
import com.bachongLightNovel.model.dto.system.SystemUserAssignDto;
import com.bachongLightNovel.model.dto.system.SystemUserPageDto;
import com.bachongLightNovel.model.vo.page.PageVo;
import com.bachongLightNovel.model.vo.system.UserInfoVo;
import com.bachongLightNovel.system.mapper.SystemUserRoleMapper;
import com.bachongLightNovel.system.service.SystemUserService;
import com.bachongLightNovel.model.dto.system.LoginDto;
import com.bachongLightNovel.error.ErrorCodeEnum;
import com.bachongLightNovel.exception.CustomException;
import com.bachongLightNovel.system.mapper.SystemUserMapper;
import com.bachongLightNovel.model.pojo.system.User;
import com.bachongLightNovel.utils.JwtUtils;
import com.bachongLightNovel.utils.UserInfoUtil;
import io.jsonwebtoken.Claims;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class SystemUserServiceImpl implements SystemUserService {

    @Autowired
    private SystemUserMapper systemUserMapper;

    @Autowired
    private SystemUserRoleMapper systemUserRoleMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 用户登录方法,返回token
     * @param dto
     * @return
     */
    @Override
    public String login(LoginDto dto) {

        //获取用户输入的用户名和密码
        String userName = dto.getUserName();
        String password = dto.getPassword();
        RLock lock = redissonClient.getLock(RedisConstant.BACHONG_LOGIN_LOCK_PREFIX + userName);
        //尝试获取锁，防止并发登录
        boolean tryLock = lock.tryLock();
        if (!tryLock) {
            throw new CustomException(ErrorCodeEnum.UNKNOW_ERROR);
        }
        try {
            //判断redis中是否含有相应token
            String isLogin = stringRedisTemplate.opsForValue().get(RedisConstant.BACHONG_LOGIN_TOKEN + userName);
            if (isLogin != null) {
                throw new CustomException(ErrorCodeEnum.ACCOUNT_OTHER_LOGIN);
            }
            //根据用户名在数据库中查找
            User user = systemUserMapper.selectByName(userName);
            if (user == null) {
                throw new CustomException(ErrorCodeEnum.USER_NOT_EXIST);
            }
            //进行密码比对
            String dbPassword = user.getPassword();
            String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
            if (!dbPassword.equals(md5Password)) {
                throw new CustomException(ErrorCodeEnum.PASSWORD_ERROR);
            }
            //生成token并返回
            Map<String, Object> claims = new HashMap<>();
            claims.put("id", user.getId());
            claims.put("username", user.getUsername());
            String token = JwtUtils.generateJwt(claims);
            //将token存入redis
            stringRedisTemplate.opsForValue().set(RedisConstant.BACHONG_LOGIN_TOKEN + userName, token,
                    RedisConstant.BACHONG_LOGIN_TIMEOUT, TimeUnit.MINUTES);
            return token;
        } finally {
            //释放锁
            lock.unlock();
        }
    }

    /**
     * 从请求头中获取登录用户的id，并获取用户信息
     * @param userId
     * @return
     */
    @Override
    public UserInfoVo getUserInfo(Long userId) {
        User user = systemUserMapper.selectById(userId);
        UserInfoVo vo = new UserInfoVo();
        BeanUtils.copyProperties(user, vo);
        vo.setUserId(user.getId());
        return vo;
    }

    /**
     * 用户条件分页列表查询
     * @param current
     * @param size
     * @param dto
     * @return
     */
    @Override
    public PageVo<User> findPage(Integer current, Integer size, SystemUserPageDto dto) {
        //查询记录总数
        Long total = systemUserMapper.count();
        //根据条件查询数据
        List<User> userList = systemUserMapper.selectByQuery((current - 1) * size, size, dto);
        //封装vo对象，并返回
        PageVo<User> vo = new PageVo<>();
        vo.setTotal(total);
        vo.setRecords(userList);
        return vo;
    }

    /**
     * 添加用户
     * @param user
     * @return
     */
    @Override
    public void saveUser(User user) {
        //得到手机号，在数据库中进行查询，存在不允许添加
        String phone = user.getPhone();
        User phUser=systemUserMapper.selectByPhone(phone);
        if (phUser!=null){
            throw new CustomException(ErrorCodeEnum.PHONE_IS_EXISTS);
        }
        //判断当前用户是否存在
        String username = user.getUsername();
        User selectByName = systemUserMapper.selectByName(username);
        if (selectByName!=null){
            throw new CustomException(ErrorCodeEnum.USER_IS_EXISTS);
        }
        //对密码进行加密
        String password = user.getPassword();
        String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
        user.setPassword(md5Password);
        systemUserMapper.insert(user);
    }

    /**
     * 修改用户信息
     * @param user
     * @return
     */
    @Override
    public void updateUser(User user) {
        //判断是否为admin用户
        if (user.getId().equals(1L)) {
            throw new CustomException(ErrorCodeEnum.ADMIN_NOT_UPDATE);
        }
        systemUserMapper.update(user);
    }

    /**
     * 根据id删除用户
     * @param id
     * @return
     */
    @Override
    public void removeById(Long id) {
        //根据id是否为1判断是否为admin用户
        if (id.equals(1L)) {
            throw new CustomException(ErrorCodeEnum.ADMIN_NOT_UPDATE);
        }
        systemUserMapper.deleteById(id);
    }

    /**
     * 为用户分配角色
     * @param dto
     * @return
     */
    @Override
    @Transactional
    public void assign(SystemUserAssignDto dto) {
        Long userId = dto.getUserId();
        systemUserRoleMapper.deleteByUserId(userId);
        systemUserRoleMapper.insertList(dto);
    }

    /**
     * 退出登录
     * @param token
     * @return Result
     */
    @Override
    public void logout(String token) {
        //获取用户名
        Claims claims = JwtUtils.parseJWT(token);
        String username = claims.get("username").toString();
        //删除相应的键
        stringRedisTemplate.delete(RedisConstant.BACHONG_LOGIN_TOKEN + username);
    }

    /**
     * 根据用户名查询用户id
     * @param auditUser :
     * @return Long
     */
    @Override
    public List<Long> getUserIdByUsername(String auditUser) {
        if (StrUtil.isBlank(auditUser)){
            throw new CustomException(ErrorCodeEnum.USER_NOT_EXIST);
        }
        List<Long> userIds = systemUserMapper.selectIdsByUsername(auditUser);
        return userIds;
    }

    /**
     * 修改密码
     * @param dto :
     * @return Result
     */
    @Override
    public void updatePassword(PasswordDto dto) {
        //获取当前登录用户的id
        Long userId = UserInfoUtil.getUser().getId();
        //如果是admin则不能被修改
        if (userId.equals(1L)){
            throw new CustomException(ErrorCodeEnum.ADMIN_NOT_UPDATE);
        }
        //根据id查询当前用户的旧密码（加密）
        String dbMd5Password = systemUserMapper.selectById(userId).getPassword();
        //对用户输入的旧密码进行md5加密，然后判断是否一致
        String md5Password=DigestUtils.md5DigestAsHex(dto.getOldPassword().getBytes());
        if (!dbMd5Password.equals(md5Password)){
            throw new CustomException(ErrorCodeEnum.PASSWORD_ERROR);
        }
        //比对成功后修改数据库
        String newMd5Password=DigestUtils.md5DigestAsHex(dto.getNewPassword().getBytes());
        //封装user对象
        User user = new User();
        user.setId(userId);
        user.setPassword(newMd5Password);
        systemUserMapper.update(user);
    }
}
